﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using T4Template.Dal;
using T4Template.Dto;
using T4Template.Entities;
using TemplateManager;

namespace T4Template.Bl
{
    class CodeGenerateBL
    {
        private CodeTemplateDal dal;

        public CodeGenerateBL()
        {
            dal = CodeTemplateDal.GetInstance();
        }

        public ActionResultDto<CodeTemplateDto> Generate(GenerateCodeDto dto)
        {
            ActionResultDto<CodeTemplateDto> resultDto = new ActionResultDto<CodeTemplateDto>();
            try
            {
                SearchCriteria criteria = new SearchCriteria();
                criteria.CodeType = dto.CodeType;
                criteria.PatternType = dto.PatternType;
                CodeTemplate foundTemplate = dal.Get(criteria);
                if (foundTemplate == null)
                {
                    throw (new Exception("Error : Found null Template"));
                }
                resultDto.Status = GenerateCode(dto.ClassModel, foundTemplate, dto.ToDirectory);
                
                ComplexTemplate t = new ComplexTemplate();
                t.ProjectPath = dto.StartupProjectDirectory;
                IProject p = t.CreateNewProject(dto.SolutionName, dto.CompleteProjectDirectory,
                                                dto.DalProjectName, dto.BlProjectName, dto.MvcProjectName);
                p.AddFile(dto.ToDirectory);
            }
            catch(Exception ex)
            {
                resultDto.Status = false;
                resultDto.ErrorMessage = ex.Message;
            }

            return resultDto;
        }

        private bool GenerateCode(ClassModelDto classModel, CodeTemplate tempaleDto, String toDirectory)
        {
            bool result = true;

            List<string> nsList = tempaleDto.TemplateNameSpaceList;

            Assembly assembly = Assembly.GetExecutingAssembly();
            foreach (string ns in nsList)
            {               
                Type[] typelist = assembly.GetTypes().Where(t => String.Equals(t.Namespace, ns, StringComparison.Ordinal)).ToArray();
                foreach (Type t in typelist)
                {
                    try
                    {
                        dynamic codeObject = Activator.CreateInstance(t);
                        codeObject.ClassModel = classModel;
                        String code = GetGenerateCode(codeObject);
                        if (code != null)
                        {
                            WriteToFile(code, toDirectory, codeObject.GetFilePath());
                        }
                    }
                    catch (Exception ex)
                    {
                    }
                }
            }

            List<string> cnList = tempaleDto.TemplateClassNameList;
            foreach (string cn in cnList)
            {              
                try
                {
                    Type classTpe = Type.GetType(cn);
                    dynamic codeObject = Activator.CreateInstance(classTpe);
                    codeObject.ClassModel = classModel;
                    String code = GetGenerateCode(codeObject);
                    if (code == null)
                    {
                        throw (new Exception("Generate Code is null"));
                    }
                    WriteToFile(code, toDirectory, codeObject.GetFilePath());
                }
                catch (Exception ex)
                {
                    result = false;
                    Console.Write("Generate Error from " + cn + " : " + ex.Message);
                }
            }

            return result;
        }

        private string GetGenerateCode(dynamic codeObject)
        {
            string resultCode = null;

            try
            {
                resultCode = codeObject.TransformText();
            }
            catch(Exception ex)
            {
                Console.Write("Generate Error from " + codeObject.GetFilePath() + " : " + ex.Message);
            }

            return resultCode;
        }

        private bool WriteToFile(string code, string toDirectory, string toFile)
        {
            bool resultCode = false;
            string filePath = toDirectory + "\\" + toFile;
            try
            {
                string destDirectory = Path.GetDirectoryName(filePath);
                System.IO.Directory.CreateDirectory(destDirectory);
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                }
                System.IO.StreamWriter file = new System.IO.StreamWriter(filePath);
                file.WriteLine(code);
                file.Close();

                resultCode = true;
            }
            catch (Exception ex)
            {
                Console.Write("Write Error from " + filePath + " : " + ex.Message);
            }

            return resultCode;
        }
    }
}
